﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Messaging;
using JiveMessenger.Converters;
using JiveMessenger.ImagePreview;
using JiveMessenger.Utilities;
using JiveMessenger.ViewModels;
using NLog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WpfAnimatedGif;

namespace JiveMessenger.Views
{
    /// <summary>
    /// Interaction logic for ImagePreviewWindow.xaml
    /// </summary>
    public partial class ImagePreviewWindow : Window, INotifyPropertyChanged
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        private Size _videoSize;
        public Size VideoSize
        {
            get { return _videoSize; }
            set
            {
                if (_videoSize != value)
                {
                    UpdatePosition(value.Width, value.Height);
                    _videoSize = value;
                    RaisePropertyChanged("VideoSize");
                }
            }
        }



        private string _videoUrl;
        public string VideoUrl
        {
            get { return _videoUrl; }
            set
            {
                if (_videoUrl != value)
                {
                    _videoUrl = value;
                    RaisePropertyChanged("VideoUrl");
                }
            }
        }

        private BitmapSource _imgSource;
        public BitmapSource ImgSource
        {
            get { return _imgSource; }
            set
            {
                if (_imgSource != value)
                {
                    if (value != null)
                        UpdatePosition(value.PixelWidth, value.PixelHeight);

                    _imgSource = value;
                    if (value == null)
                        ImgControl.Source = null;
                    RaisePropertyChanged("ImgSource");
                }
            }
        }

        private int _imgNumber;
        public int ImgNumber
        {
            get { return _imgNumber; }
            set
            {
                if (_imgNumber != value)
                {
                    _imgNumber = value;
                    RaisePropertyChanged("ImgNumber");
                }
            }
        }

        private int _imgCount;
        public int ImgCount
        {
            get { return _imgCount; }
            set
            {
                if (_imgCount != value)
                {
                    _imgCount = value;
                    RaisePropertyChanged("ImgCount");
                    if (ImgCount > 1)
                        IsAlbumInfoVisible = IsWindowVisible;
                }
            }
        }

        private string _imageText;
        public string ImageText
        {
            get { return _imageText; }
            set
            {
                if (_imageText != value)
                {
                    _imageText = value;
                    RaisePropertyChanged("ImageText");
                    if (!string.IsNullOrEmpty(value))
                        IsTextVisible = IsWindowVisible;
                    else
                        IsTextVisible = false;
                }
            }
        }

        private bool _isWindowVisible;
        public bool IsWindowVisible
        {
            get { return _isWindowVisible; }
            set
            {
                if (_isWindowVisible != value)
                {
                    _isWindowVisible = value;
                    RaisePropertyChanged("IsWindowVisible");
                    IsTextVisible = !String.IsNullOrEmpty(this.ImageText);
                    IsAlbumInfoVisible = this.ImgCount > 1;
                    if (value == true)
                    {
                        if (value == false)
                        { }
                    }
                }
            }
        }

        private bool _isTextVisible;
        public bool IsTextVisible
        {
            get { return _isTextVisible; }
            set
            {
                if (_isTextVisible != value)
                {
                    _isTextVisible = value;
                    RaisePropertyChanged("IsTextVisible");
                }
            }
        }


        private bool _isAlbumInfoVisible;
        public bool IsAlbumInfoVisible
        {
            get { return _isAlbumInfoVisible; }
            set
            {
                if (_isAlbumInfoVisible != value)
                {
                    _isAlbumInfoVisible = value;
                    RaisePropertyChanged("IsAlbumInfoVisible");
                }
            }
        }

        public ImagePreviewWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.LayoutRoot.Opacity = 0;
        }


        ~ImagePreviewWindow()
        {
        }

        public void UpdatePosition(Size size)
        {
            UpdatePosition(size.Width, size.Height);
        }
        public void UpdatePosition(double width = -1, double height = -1)
        {
            this.ImgControl.Stretch = Stretch.Fill;
            double newWidth = width;
            double newHeight = height;
            if (width <= 0)
            {
                if (ImgSource != null)
                    newWidth = ImgSource.PixelWidth;
                else
                    newWidth = ImgPanel.ActualWidth;
            }
            if (height <= 0)
            {
                if (ImgSource != null)
                    newHeight = ImgSource.PixelHeight;
                else
                    newHeight = ImgPanel.ActualHeight;
            }
            //if (newWidth / newHeight > 2.5)
            //    this.ImgControl.Stretch = Stretch.None;
            //newWidth = newWidth * 1-(this.TitleGrid.ActualHeight / (newHeight - this.TitleGrid.ActualHeight));
            //newHeight-= this.TitleGrid.ActualHeight;
            var formattedText = new FormattedText(
                                        ImageText??"",
                                        CultureInfo.CurrentUICulture,
                                        FlowDirection.LeftToRight,
                                        new Typeface(this.TitleTextBlock.FontFamily, this.TitleTextBlock.FontStyle, this.TitleTextBlock.FontWeight, this.TitleTextBlock.FontStretch),
                                        this.TitleTextBlock.FontSize,
                                        Brushes.Black);
            double newTop = 0;
            double newLeft = 0;


            double maxHeight = (System.Windows.SystemParameters.WorkArea.Height - formattedText.Height) / 1.1;
            //Debug.WriteLine("maxheight: " + maxHeight);
            //Debug.WriteLine("title height: " + formattedText.Height);
            double maxWidth = System.Windows.SystemParameters.WorkArea.Width / 1.2;

            if (newWidth > maxWidth)
            {
                double ratio = (maxWidth) / newWidth;
                newWidth = maxWidth;
                newHeight = newHeight * ratio;
            }
            if (newHeight > maxHeight)
            {
                double ratio = (maxHeight) / newHeight;
                newHeight = maxHeight;
                newWidth = newWidth * ratio;
            }


            W32Point pt = new W32Point();
            if (!Win32.GetCursorPos(ref pt))
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }

            // 0x00000002: return nearest monitor if pt is not contained in any monitor.
            IntPtr monHandle = Win32.MonitorFromPoint(pt, 0x00000002);
            W32MonitorInfo monInfo = new W32MonitorInfo();
            monInfo.Size = Marshal.SizeOf(typeof(W32MonitorInfo));

            if (!Win32.GetMonitorInfo(monHandle, ref monInfo))
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
            // use WorkArea struct to include the taskbar position.
            W32Rect monitor = monInfo.WorkArea;
            Rect screen = new Rect(
    new Point(monitor.Left, monitor.Top),
    new Point(monitor.Right, monitor.Bottom - 50));

            double offsetX = Math.Round(newWidth) + 30;// / 2);
            double offsetY = Math.Round(newHeight / 2);

            double top = pt.Y - offsetY;
            double left;
            if ((pt.X - screen.Left) < (screen.Width / 2))
            {
                left = pt.X + 30;
            }
            else
            {
                left = pt.X - offsetX;
            }


            Rect wnd = new Rect(
                new Point(left, top),
                new Point(left + newWidth, top + newHeight));

            top = wnd.Top;
            left = wnd.Left;

            if (!screen.Contains(wnd))
            {
                if (wnd.Top < screen.Top)
                {
                    double diff = Math.Abs(screen.Top - wnd.Top);
                    top = wnd.Top + diff;
                }

                if (wnd.Bottom > screen.Bottom)
                {
                    double diff = wnd.Bottom - screen.Bottom + 50;
                    top = wnd.Top - diff;
                }
                if (top == 0)
                    top = 30;
                if (wnd.Left < screen.Left)
                {
                    double diff = Math.Abs(screen.Left - wnd.Left);
                    left = screen.Left;
                    double ratio = (newWidth - diff) / newWidth;
                    newWidth = newWidth - diff;
                    newHeight = newHeight * ratio;
                }

                if (wnd.Right > screen.Right)
                {
                    double diff = wnd.Right - screen.Right;
                    left = wnd.Left;
                    double ratio = (newWidth - diff) / newWidth;
                    newWidth = newWidth - diff;
                    newHeight = newHeight * ratio;
                }
            }

            newTop = top;
            newLeft = left;

            this.Top = newTop;
            this.Left = newLeft;
            // Debug.WriteLine(this.id + string.Format(" top:{0}, left{1}", newTop, newLeft));
            this.ImgPanel.Width = newWidth;
            this.ImgPanel.Height = newHeight;
        }

        private void ImgControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Logger.Debug("Image preview size changed to: {0}x{1} px", e.NewSize.Width, e.NewSize.Height);
            this.TitleGrid.Width = e.NewSize.Width;
        }

        private void VideoMediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            Messenger.Default.Send(new NotificationMessage<bool>(this, false, "ShowDownloadProgressWindow"));
            if (this.VideoMediaElement.Source == null)
                return;
            if (String.IsNullOrEmpty(VideoUrl))
                return;


            double width = 400;
            double height = 200;
            if (this.VideoMediaElement.NaturalVideoHeight > 0 && this.VideoMediaElement.NaturalVideoWidth > 0)
            {
                width = this.VideoMediaElement.NaturalVideoWidth;
                height = this.VideoMediaElement.NaturalVideoHeight;
            }
            UpdatePosition(width, height);
            //    this.VideoLoadingPanel.Visibility = System.Windows.Visibility.Visible;
            //   Logger.Debug("Showing video loading panel in VideoMediaElement_MediaOpened");
            Debug.WriteLine("Video element opened");
        }

        //private void VideoMediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        //{
        //    Logger.ErrorException("Error loading video file", e.ErrorException);

        //    Messenger.Default.Send(new NotificationMessage<int>(this, 404, "SetDownloadErrorCode"));

        //}

        private void VideoMediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            //MediaElement me = (MediaElement)sender;
            //me.Position = TimeSpan.Zero;
        }

        private void VideoMediaElement_TargetUpdated(object sender, DataTransferEventArgs e)
        {
            //  MediaElement me = sender as MediaElement;
            //  var vm = this.DataContext as ViewModelImagePreviewWindow;
            if (!string.IsNullOrEmpty(VideoUrl))
            {

                Logger.Debug("Setting video url to: " + VideoUrl);
                Task.Factory.StartNew(() =>
                    {
                        // Set is never called, so we wait always until the timeout occurs
                        using (EventWaitHandle tmpEvent = new ManualResetEvent(false))
                        {
                            tmpEvent.WaitOne(TimeSpan.FromMilliseconds(50));
                        }
                        this.Dispatcher.Invoke(() =>
                            {
                                if (VideoMediaElement.MediaDuration == 0)
                                {
                                    Logger.Debug("Showing video loading panel in VideoMediaElement_TargetUpdated");
                                    this.VideoLoadingPanel.Visibility = System.Windows.Visibility.Visible;
                                }
                            });
                    });
                Messenger.Default.Send(new NotificationMessage<bool>(this, false, "ShowDownloadProgressWindow"));
                double width = 400;
                double height = 200;
                if (this.VideoMediaElement.NaturalVideoHeight > 0 && this.VideoMediaElement.NaturalVideoWidth > 0)
                {
                    width = this.VideoMediaElement.NaturalVideoWidth;
                    height = this.VideoMediaElement.NaturalVideoHeight;
                }
                UpdatePosition(width, height);
                //    me.Play();
                Logger.Debug("Starting video playback");
            }
            else
            {
                this.VideoLoadingPanel.Visibility = System.Windows.Visibility.Collapsed;
                Logger.Debug("Hiding video loading panel in targetupdated");
            }
        }

        public void PauseGif()
        {
            this.Dispatcher.Invoke(() =>
                {
                    if (this.ImgControl != null)
                    {
                        ImageAnimationController control = ImageBehavior.GetAnimationController(this.ImgControl);
                        if (control != null)
                        {
                            control.GotoFrame(0);
                            control.Pause();
                            Logger.Debug("Pausing gif");
                        }
                    }
                });

        }

        public void PlayGif()
        {

            this.Dispatcher.Invoke(() =>
                {
                    Image img = this.ImgControl;
                    if (img != null)
                    {
                        ImageAnimationController control = ImageBehavior.GetAnimationController(img);
                        if (control != null)
                        {
                            control.Play();
                            Logger.Debug("Playing gif");
                        }
                    }
                });

        }

        private void ShowLayoutStoryboard_Completed(object sender, EventArgs e)
        {
            Storyboard sb = this.Resources["ShowLayout"] as Storyboard;
            sb.Completed -= ShowLayoutStoryboard_Completed;
            Logger.Debug("Layout is now visible");
            if (ImgSource != null)
            {
                PlayGif();
            }
            else if (!String.IsNullOrEmpty(VideoUrl))
            {
                this.VideoMediaElement.Play();
                UpdatePosition(this.VideoMediaElement.NaturalVideoWidth, this.VideoMediaElement.NaturalVideoHeight);
                Logger.Debug("Starting video playback");
            }
        }

        private void HideLayoutStoryboard_Completed(object sender, EventArgs e)
        {
            Storyboard sb = this.Resources["HideLayout"] as Storyboard;
            sb.Completed -= HideLayoutStoryboard_Completed;

            if (ImgSource != null)
            {
                PauseGif();
            }
            else if (!String.IsNullOrEmpty(VideoUrl))
            {
                this.VideoMediaElement.Close();
                this.VideoLoadingPanel.Visibility = System.Windows.Visibility.Collapsed;
                Logger.Debug("Hiding video loading panel in HideLayoutStoryboard_Completed");
                Logger.Debug("Stopping video playback");
            }
        }


        private void ImgPreviewWindow_Closed(object sender, EventArgs e)
        {
            this.VideoMediaElement.Source = null;
            Debug.WriteLine("ImagePreviewWindow closed");
        }

        private void ImgPreviewWindow_Loaded(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("creating image preview window");
        }


        private void ImgPreviewWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            this.VideoMediaElement.Close();
            IsWindowVisible = false;
            ImgSource = null;
            VideoUrl = null;
        }

        private void VideoMediaElement_MediaFailed(object sender, WPFMediaKit.DirectShow.MediaPlayers.MediaFailedEventArgs e)
        {
            Logger.ErrorException("Error loading video file", e.Exception);
            this.Dispatcher.BeginInvoke(() =>
                {
                    this.VideoLoadingTextLabel.Content = e.Message;
                    this.VideoLoadingPanel.Background = new SolidColorBrush(Colors.Red);
                });
        }

        private void VideoMediaElement_MediaClosed(object sender, RoutedEventArgs e)
        {
            this.VideoLoadingPanel.Visibility = System.Windows.Visibility.Collapsed;
            Logger.Debug("Hiding video loading panel in mediaclosed");
        }

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        private void ImgControl_Unloaded(object sender, RoutedEventArgs e)
        {

        }
    }
}
